﻿/*  
	========================================================================
	 awzBoxes Library
	
	 Homepage: http://www.awzhome.de/
	========================================================================
	
	This Source Code Form is subject to the terms of the Mozilla Public
	License, v. 2.0. If a copy of the MPL was not distributed with this
	file, You can obtain one at http://mozilla.org/MPL/2.0/.
   
	The Original Code is code of awzBoxes Library.

	The Initial Developer of the Original Code is Andreas Weizel.
	Portions created by the Initial Developer are
	Copyright (C) 2011-2012 Andreas Weizel. All Rights Reserved.
	
	Contributor(s): (none)
	
	========================================================================
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using AWZhome.awzBoxes.Tools;

namespace AWZhome.awzBoxes
{
	/// <summary>
	/// Interaction logic for FloatingWindow.xaml
	/// </summary>
	public partial class FloatingWindow : Window
	{
		private BoxWindowContainer _parentBoxWindowContainer;
		private bool _isClosing = false;

		internal FloatingWindow(BoxWindowContainer parentBoxWindowContainer, BoxItem boxItem)
		{
			_parentBoxWindowContainer = parentBoxWindowContainer;
			this.FloatingBoxItem = boxItem;
			this.DataContext = boxItem;

			// Undock if not already done
			if (boxItem.Direction != BoxItemDockDirection.NotDocking)
			{
				boxItem.Undock();
			}

			boxItem._Direction = BoxItemDockDirection.Floating;
			boxItem.ParentFloatingWindow = this;

			InitializeComponent();

			// Add client control to the window
			if (boxItem.Content != null)
			{
				floatingBoxItemContainer.Children.Add(boxItem.Content);
			}

			// Find the main window containing the BoxWindowContainer and set it as owner of the floating window
			if (parentBoxWindowContainer != null)
			{
				if (!parentBoxWindowContainer.FloatingWindowsList.Contains(this))
				{
					parentBoxWindowContainer.FloatingWindowsList.Add(this);
				}
				Window mainWindow = ControlFinder.FindAncestor<Window>(parentBoxWindowContainer);
				if (mainWindow != null)
				{
					this.Owner = mainWindow;
				}
			}
		}

		/// <summary>
		/// Returns the <see cref="AWZhome.awzBoxes.BoxItem"/> that is
		/// embedded in the FloatingWindow.
		/// </summary>
		public BoxItem FloatingBoxItem
		{
			get;
			private set;
		}

		/// <summary>
		/// Returns the parent <see cref="AWZhome.awzBoxes.BoxWindowContainer"/>
		/// instance for this FloatingWindow.
		/// </summary>
		public BoxWindowContainer ParentBoxWindowContainer
		{
			get
			{
				return _parentBoxWindowContainer;
			}
		}

		/// <summary>
		/// Returns whether the <see cref="AWZhome.awzBoxes.BoxItem"/> is allowed to leave
		/// the floating state.
		/// </summary>
		internal bool IsRedockingAllowed
		{
			get
			{
				if (this.FloatingBoxItem != null)
				{
					return ((this.FloatingBoxItem.AllowedDockAreas & ~BoxItemDockDirection.Floating) != BoxItemDockDirection.NotDocking);
				}
				else
				{
					return false;
				}
			}
		}

		private void FloatingBoxItemRedockCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void FloatingBoxItemRedockCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			BoxItem boxItem = this.FloatingBoxItem;
			if (boxItem != null)
			{
				_isClosing = true;

				// Simply dock the BoxItem to an allowed direction
				if ((boxItem.AllowedDockAreas & BoxItemDockDirection.DockInnerArea) == BoxItemDockDirection.DockInnerArea)
				{
					boxItem.Direction = BoxItemDockDirection.DockInnerArea;
				}
				else if ((boxItem.AllowedDockAreas & BoxItemDockDirection.DockLeft) == BoxItemDockDirection.DockLeft)
				{
					boxItem.Direction = BoxItemDockDirection.DockLeft;
				}
				else if ((boxItem.AllowedDockAreas & BoxItemDockDirection.DockRight) == BoxItemDockDirection.DockRight)
				{
					boxItem.Direction = BoxItemDockDirection.DockRight;
				}
				else if ((boxItem.AllowedDockAreas & BoxItemDockDirection.DockTop) == BoxItemDockDirection.DockTop)
				{
					boxItem.Direction = BoxItemDockDirection.DockTop;
				}
				else if ((boxItem.AllowedDockAreas & BoxItemDockDirection.DockBottom) == BoxItemDockDirection.DockBottom)
				{
					boxItem.Direction = BoxItemDockDirection.DockBottom;
				}

				// This is more a workaround: Make the BoxItem active explicitly.
				boxItem.IsActive = true;
			}
		}

		private void FloatingBoxItemCloseCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void FloatingBoxItemCloseCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			if (this.FloatingBoxItem != null)
			{
				_isClosing = true;
				this.FloatingBoxItem.Close();
			}
		}

		private void FloatingBoxItemMaximizeCommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
		{
			e.CanExecute = true;
		}

		private void FloatingBoxItemMaximizeCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
		{
			// Maximize or restore the window
			if (this.WindowState == System.Windows.WindowState.Normal)
			{
				this.WindowState = System.Windows.WindowState.Maximized;
			}
			else if (this.WindowState == System.Windows.WindowState.Maximized)
			{
				this.WindowState = System.Windows.WindowState.Normal;
			}
		}

		private void Window_Loaded(object sender, RoutedEventArgs e)
		{
			// Add event handler for moving the window
			Label titleLabel = this.GetTemplateChild("PART_TitleLabel") as Label;
			if (titleLabel != null)
			{
				titleLabel.MouseLeftButtonDown += new MouseButtonEventHandler(titleLabel_MouseLeftButtonDown);
			}

			// Add event handler for the resize thumbs in the template
			Thumb resizeThumb = this.GetTemplateChild("PART_NWResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += NWResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_NResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += NResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_NEResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += NEResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_WResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += WResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_EResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += EResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_SWResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += SWResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_SResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += SResizeThumb_DragDelta;
			}
			resizeThumb = this.GetTemplateChild("PART_SEResizeThumb") as Thumb;
			if (resizeThumb != null)
			{
				resizeThumb.DragDelta += SEResizeThumb_DragDelta;
			}
		}

		private void titleLabel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
		{
			this.Opacity = 0.4;
			this.DragMove();
			this.Opacity = 1;
		}

		private void Window_Closed(object sender, EventArgs e)
		{
			// Window has been closed externally and not from the BoxItem, so close BoxItem explicitly
			if (!_isClosing)
			{
				if (this.FloatingBoxItem != null)
				{
					_isClosing = true;
					this.FloatingBoxItem.Close();
				}
			}

			// Remove the window from internal list
			if (_parentBoxWindowContainer != null)
			{
				_parentBoxWindowContainer.FloatingWindowsList.Remove(this);
			}
			if (this.FloatingBoxItem != null)
			{
				this.FloatingBoxItem.ParentFloatingWindow = null;
			}
			floatingBoxItemContainer.Children.Clear();
		}

		private void NWResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag north and west side
			NResizeThumb_DragDelta(sender, e);
			WResizeThumb_DragDelta(sender, e);
		}

		private void NResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag north side
			double yadjust = this.Height - e.VerticalChange;
			double yadjustOffset = this.Top + e.VerticalChange;
			if (yadjust >= 0)
			{
				this.Height = yadjust;
				this.Top = yadjustOffset;
			}
		}

		private void NEResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag north and east side
			NResizeThumb_DragDelta(sender, e);
			EResizeThumb_DragDelta(sender, e);
		}

		private void WResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag west side
			double xadjust = this.Width - e.HorizontalChange;
			double xadjustOffset = this.Left + e.HorizontalChange;
			if (xadjust >= 0)
			{
				this.Width = xadjust;
				this.Left = xadjustOffset;
			}
		}

		private void EResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag east side
			double xadjust = this.Width + e.HorizontalChange;
			if (xadjust >= 0)
			{
				this.Width = xadjust;
			}
		}

		private void SWResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag south and west side
			SResizeThumb_DragDelta(sender, e);
			WResizeThumb_DragDelta(sender, e);
		}

		private void SResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag south side
			double yadjust = this.Height + e.VerticalChange;
			if (yadjust >= 0)
			{
				this.Height = yadjust;
			}
		}

		private void SEResizeThumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			// Drag south and east side
			SResizeThumb_DragDelta(sender, e);
			EResizeThumb_DragDelta(sender, e);
		}
	}
}
